package com.example.chenjun.myapplication.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;

import com.example.chenjun.myapplication.R;
import com.example.chenjun.myapplication.util.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * @author chenj
 * @date 2018/3/16 0016
 */

public class AutoNewLineLayout extends ViewGroup {

    private int mPaddingBottom;
    private int mPaddingTop;
    private int mPaddingLeft;
    private int mPaddingRight;
    private List<Size> mChildSizes;
    private List<Integer> mLineHeightList;
    private int mRealTotalChildWidth;
    private int mWeight;

    public AutoNewLineLayout(Context context) {
        this(context, null);
    }

    public AutoNewLineLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoNewLineLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaddingBottom = getPaddingBottom();
        mPaddingLeft = getPaddingLeft();
        mPaddingRight = getPaddingRight();
        mPaddingTop = getPaddingTop();
        mChildSizes = new ArrayList<>();
        mLineHeightList = new ArrayList<>();
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoNewLineLayout);
        mWeight = a.getInt(R.styleable.AutoNewLineLayout_weight, 0);
        a.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        reset();
        mRealTotalChildWidth = getMeasuredWidth() - mPaddingRight - mPaddingLeft;
        int childCount = getChildCount();
        int currentTotalWidth = 0;
        int currentTotalHeight = mPaddingTop;
        int lineHeight = 0;
        for (int i = 0; i < childCount; i++) {
            View childView = getChildAt(i);
            Size size = measureChildSize(childView, widthMeasureSpec, heightMeasureSpec);
            if (currentTotalWidth != 0 && size.realWidth + currentTotalWidth > mRealTotalChildWidth) {
                currentTotalWidth = 0;
                mLineHeightList.add(lineHeight);
                initChildInfo(currentTotalHeight);
                currentTotalHeight += lineHeight;
                lineHeight = 0;
                i--;
            } else {
                currentTotalWidth += size.realWidth;
                lineHeight = Math.max(lineHeight, size.realHeight);
                size.lineIndex = mLineHeightList.size();
                mChildSizes.add(size);
                if (i == childCount - 1) {
                    mLineHeightList.add(lineHeight);
                    initChildInfo(currentTotalHeight);
                    currentTotalHeight += lineHeight;
                    currentTotalHeight += mPaddingBottom;
                }
            }
        }
        setMeasuredDimension(getMeasuredWidth(), currentTotalHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        for (int i = 0; i < mChildSizes.size(); i++) {
            View child = getChildAt(i);
            Rect rect = mChildSizes.get(i).mRect;
            child.layout(rect.left, rect.top, rect.right, rect.bottom);
        }
    }

    private void reset() {
        mChildSizes.clear();
        mLineHeightList.clear();
        mRealTotalChildWidth = 0;
    }


    private void initChildInfo(int top) {
        int index = mLineHeightList.size() - 1;
        int left = mPaddingLeft;
        for (Size size : mChildSizes) {
            if (size.lineIndex != index) {
                continue;
            }
            int currentLeft = left + size.leftMargin;
            int currentTop = getChildTopLoc(top, mLineHeightList.get(index), size);
            size.mRect = new Rect(currentLeft, currentTop, currentLeft + size.width, currentTop + size.height);
            left += size.realWidth;
        }
    }

    private int getChildTopLoc(int top, int lineHeight, Size childSize) {
        switch (childSize.gravity) {
            case Gravity.TOP:
                return top + childSize.topMargin;
            case Gravity.BOTTOM:
                return top + lineHeight - childSize.bottomMargin - childSize.height;
            case Gravity.CENTER:
            case Gravity.CENTER_VERTICAL:
                return top + (lineHeight - childSize.realHeight) / 2 + childSize.topMargin;
            default:
                return top + childSize.topMargin;
        }
    }

    private Size measureChildSize(View child, int widthMeasureSpec, int heightMeasureSpec) {
        measureChild(child, widthMeasureSpec, heightMeasureSpec);
        int measuredHeight = child.getMeasuredHeight();
        int measuredWidth = child.getMeasuredWidth();
        LayoutParams params = (LayoutParams) child.getLayoutParams();
        int topMargin = params.topMargin;
        int bottomMargin = params.bottomMargin;
        int leftMargin = params.leftMargin;
        int rightMargin = params.rightMargin;
        int realHeight = measuredHeight + topMargin + bottomMargin;
        int realWidth = measuredWidth + leftMargin + rightMargin;
        if (mWeight != 0) {
            realWidth = (int) (params.weight / mWeight * mRealTotalChildWidth);
            if (realWidth > mRealTotalChildWidth) {
                realWidth = mRealTotalChildWidth;
            }
            int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(realWidth - leftMargin - rightMargin, MeasureSpec.EXACTLY);
            measureChild(child, newWidthMeasureSpec, heightMeasureSpec);
        }
        return new Size(realWidth, realHeight, leftMargin, topMargin, rightMargin, bottomMargin, params.gravity);
    }

    public static class LayoutParams extends MarginLayoutParams {

        public int gravity = Gravity.TOP;
        public float weight;

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);
            TypedArray a =
                    c.obtainStyledAttributes(attrs, android.support.v7.appcompat.R.styleable.LinearLayoutCompat_Layout);
            gravity = a.getInt(android.support.v7.appcompat.R.styleable.LinearLayoutCompat_Layout_android_layout_gravity, Gravity.TOP);
            weight = a.getFloat(android.support.v7.appcompat.R.styleable.LinearLayoutCompat_Layout_android_layout_weight, 0);
            a.recycle();
        }

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(MarginLayoutParams source) {
            super(source);
        }

        public LayoutParams(ViewGroup.LayoutParams source) {
            super(source);
        }

    }

    @Override
    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
        if (p instanceof LayoutParams) {
            return (LayoutParams) p;
        }
        return new LayoutParams(p);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    private class Size {
        int realWidth;
        int realHeight;
        int gravity;
        int lineIndex;
        Rect mRect;
        int leftMargin;
        int topMargin;
        int rightMargin;
        int bottomMargin;
        int height;
        int width;

        Size(int width, int height, int leftMargin, int topMargin, int rightMargin, int bottomMargin, int gravity) {
            realHeight = height;
            realWidth = width;
            this.gravity = gravity;
            this.leftMargin = leftMargin;
            this.topMargin = topMargin;
            this.rightMargin = rightMargin;
            this.bottomMargin = bottomMargin;
            this.height = realHeight - bottomMargin - topMargin;
            this.width = realWidth - leftMargin - rightMargin;
        }
    }
}
